%error-verbose
%{
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "symbol_table.h"
int yyerror(char *);

struct node
	{
		
		char *value;
		struct node *rightchild;
		struct node *leftchild;
	};
	struct node * treenode();
	void addchild(struct node *parent,struct node *lhs, struct node *rhs);
	static struct node *root=NULL;

/*installing a token into symbol table*/
install (char *sym_name)
{
	sym_tab_rec *s;
	s = getsym(sym_name);
	if(s == 0)
	s = putsym(sym_name);
	else
	{
		printf("\n%s is already defined\n",sym_name);
	}
}

context_check(char *sym_name)
{
	if(getsym(sym_name) == 0)
	{
		if(getsym(sym_name) == 0)
		printf("\n%s is an undeclared identifier\n",sym_name);
	}
}
	
%}

/*SEMANTIC RECORD*/
%union 
{ 
	char *id;	/*For returning identifier */
	int intval;
}	

%token <id> IDENTIFIER
%token INDENT
%token DEDENT
%token NEWLINE
%token STRING
%token BREAK
%token DEF
%token IF
%token ELSE
%token ELIF
%token PASS
%token CONTINUE
%token NUMBER
%token LETTER
%token WHILE
%token FOR
%token AND
%token DEL
%token FROM
%token NOT
%token AS
%token GLOBAL
%token OR
%token WITH
%token ASSERT
%token YIELD
%token EXCEPT
%token IMPORT
%token CLASS
%token EXEC
%token IN
%token RAISE
%token FINALLY
%token IS
%token RETURN
%token LAMBDA
%token TRY
%token FRACTION
%token EXPONENT
%token EQUAL
%token EQ
%token LT
%token GT
%token NE
%token LE
%token GE
%token COMMA
%token SEMICOLON
%token COLON
%token INCEQ
%token DECEQ
%token MULEQ
%token DIVEQ
%token MODEQ
%token ANDEQ
%token OREQ
%token NOTEQ
%token LSFTEQ
%token RSFTEQ
%token EXPEQ
%token DOT
%token BRACES
%token LP
%token RP
%token PLUS
%token MINUS
%token TILDE
%token LB
%token RB
%token STAR
%token DIV
%token LCB
%token RCB
%token PERCENT
%token DSLASH
%token PRINT
%token AMPRSND
%token PIPE
%token CAP

%left '+' '-'
%left '*' '/'

%start file_input

%%

file_input: 	  strt 
		| strt file_input;

strt: NEWLINE | stmt ;

func_def: DEF IDENTIFIER parameters COLON suite {printf("Fndef: ");install($2)};

parameters: LP RP | LP varargslist RP;

varargslist: varargslist_sub1 varargslist_sub2 | varargslist_sub3;

varargslist_sub1: /*emptylist*/ | varargslist_sub1_option varargslist_sub1;

varargslist_sub1_option: fpdef COMMA | fpdef EQ test COMMA;

varargslist_sub2: varargslist_sub2_option | STAR STAR IDENTIFIER;

varargslist_sub2_option: STAR IDENTIFIER | STAR IDENTIFIER COMMA STAR STAR IDENTIFIER;

varargslist_sub3: fpdef varargslist_sub3_option2 varargslist_sub3_option1 varargslist_sub3_option3;

varargslist_sub3_option1: /*empty*/ | COMMA fpdef varargslist_sub3_option1 | COMMA fpdef EQ test varargslist_sub3_option1;

varargslist_sub3_option2: /*empty*/ | EQ test;

varargslist_sub3_option3: /*empty*/ | COMMA;

fpdef: IDENTIFIER | LP fplist RP;

fplist: fpdef fpdef_rec | fpdef fpdef_rec COMMA;

fpdef_rec: /*empty*/ | COMMA fpdef fpdef_rec;

stmt: simple_stmt| compound_stmt {printf("stmt\n");};

simple_stmt:	  small_stmt simple_stmt_rec NEWLINE {printf("Simple_stmt\n");}
		| small_stmt simple_stmt_rec SEMICOLON NEWLINE;

simple_stmt_rec: /*emptylist*/ {printf("Empty\n");}
		| SEMICOLON small_stmt simple_stmt_rec;

small_stmt: 	  print_stmt {printf("Print_stmt\n");}
		| assign_stmt| expr_stmt| del_stmt
		| pass_stmt| flow_stmt| global_stmt;

print_stmt:       PRINT tests {printf("Tests\n");}
		| PRINT GT GT test 
		| PRINT GT GT test tests_rec;

tests:    /*empty*/ 
	| test tests_rec {printf("Tests empty\n");};

tests_rec: /*emptylist*/  
	   | COMMA test tests_rec;

pass_stmt: PASS;

flow_stmt: break_stmt | continue_stmt | return_stmt;

break_stmt: BREAK;

continue_stmt: CONTINUE;

return_stmt:      RETURN 
		| RETURN testlist;

global_stmt:      GLOBAL var_rec;

var_rec:  IDENTIFIER
	| IDENTIFIER COMMA var_rec;

assign_stmt: IDENTIFIER EQUAL expr { install($1);};

expr_stmt: testlist expr_list;

expr_list: expr_list1 | expr_list2;

expr_list1: augassign expr_list_sub;

expr_list2:     /*empty*/

		| EQUAL expr_list_sub expr_list2;

expr_list_sub: yield_expr| testlist;

augassign:  INCEQ| DECEQ | MULEQ | DIVEQ | MODEQ | ANDEQ | OREQ | NOTEQ | LSFTEQ | RSFTEQ | EXPEQ;

compound_stmt:     if_stmt | func_def {printf("Func_def\n")}
	 	 | while_stmt | classdef;

if_stmt:   IF test COLON suite
	 | IF test COLON suite elifs;

elifs:    ELIF test COLON suite
	| ELSE COLON suite
	| ELIF test COLON suite elifs;

while_stmt:       WHILE test COLON suite
		| WHILE test COLON suite ELSE COLON suite;

test:     or_test {printf("or test\n");}
	| or_test IF or_test ELSE test;

or_test: and_test orlist {printf("and test\n");};

orlist: /*emptylist*/
	| 'or' and_test orlist;

and_test: not_test andlist {printf("not test\n");};

andlist: /*emptylist*/
	| 'and' not_test andlist;

not_test: 'not' not_test | comparison {printf("comparison\n");};

comparison:        expr {printf("expr\n");}
		 | expr compexp_rec;

compexp_rec:      comp_op expr
		| comp_op expr compexp_rec;

comp_op : LT |GT|EQ|LE| GE | NE;

expr:     xor_expr xor_expr_rec {printf("xor\n");};

xor_expr_rec:   /*emptylist*/
		|  PIPE xor_expr xor_expr_rec;

xor_expr: and_expr and_expr_rec {printf("andexpr\n");};

and_expr_rec:   /*emptylist*/
		|  CAP and_expr and_expr_rec;

and_expr: shift_expr shiftexpr_rec {printf("shift\n");};

shiftexpr_rec: /*emptylist*/
		|  AMPRSND shift_expr shiftexpr_rec;

shift_expr: arith_expr arith_expr_rec {printf("arithmetic\n");};

arith_expr_rec:   /*emptylist*/
		| shift_op arith_expr arith_expr_rec;

shift_op: LT LT | GT GT;

arith_expr: term term_rec {printf("term\n");};

term_rec: /*emptylist*/
	| term_op term term_rec;

term_op: PLUS | MINUS;

term: factor factor_rec {printf("factor\n");};

factor_rec: /*emptylist*/
	| factor_op factor factor_rec;

factor_op: STAR| DIV | PERCENT | DSLASH;

factor: fact_op factor | power {printf("power\n");};

fact_op: PLUS | MINUS | TILDE;

power: atom trailer_rec {printf("atom\n");}
	| atom trailer_rec STAR STAR factor;

atom:      LP tuple RP {printf("tuple\n");}
	 | LB list  RB {printf("list\n");}
	 | LCB dict RCB {printf("dict\n");}
	 | '`' testlist1 '`' {printf("``\n");}
	 | IDENTIFIER {printf("ident\n");}
	 | NUMBER {printf("Number\n");} 
	 | strings {printf("strings\n");};

tuple:   /*emptylist*/
	| yield_expr
	|testlist_gexp;

list:   /*emptylist*/
	| listmaker;

dict:   /*emptylist*/
	| dictmaker;

strings:  STRING 
	| STRING strings;

listmaker: test list_options;

list_options: list_for | test_options;

test_options:      tests_rec 
		| tests_rec COMMA;

testlist_gexp: test testlist_gexp_options;

testlist_gexp_options: gen_for | test_options;

trailer: LP arglists RP 
	| LB subscriptlist RB
	| DOT IDENTIFIER;

arglists: /*emptylist*/	| arglist;

subscriptlist: subscript subscript_list
		| subscript subscript_list COMMA;

subscript_list:   /*emptylist*/
		| COMMA subscript subscript_list;

subscript: DOT DOT | test | subscript_option;

subscript_option: test_sub COLON test_sub sliceop_sub;

test_sub: /*emptylist*/ | test;

sliceop_sub: /*emptylist*/ | sliceop;

sliceop: COLON test_sub;

exprlist: expr expr_rec
	| expr expr_rec COMMA;

expr_rec: /*emptylist*/ | COMMA expr expr_rec;

testlist: test tests_rec
	| test tests_rec COMMA;

dictmaker: test COLON test dict_rec
	| test COLON test dict_rec COMMA;

dict_rec: /*emptylist*/
	| COMMA test COLON test dict_rec;

classdef: CLASS IDENTIFIER class_options COLON suite {install($2);};

class_options: LP RP | LP testlist RP; 

arglist: argument_rec1 arglist_option;

arglist_option: argument_opt |STAR test argument_rec2 argument_test |STAR STAR test;

argument_rec1: /*emptylist*/ | argument COMMA argument_rec1;

argument_rec2: /*emptylist*/ | COMMA argument argument_rec2;

argument_test: /*empty*/ | COMMA STAR STAR test;

argument_opt: argument | argument COMMA;

argument: test_genfor | test EQUAL test;

test_genfor: test | test gen_for;

list_iter: list_for | list_if;

list_for: FOR exprlist IN testlist_safe | FOR exprlist IN testlist_safe list_iter;

list_if: IF old_test | IF old_test list_iter;

gen_iter: gen_for | gen_if;

gen_for: FOR exprlist IN or_test | FOR exprlist IN or_test gen_iter;

gen_if: IF old_test | IF old_test gen_iter;

testlist1: test tests_rec;

yield_expr: YIELD | YIELD testlist;

trailer_rec: /*emptylist*/
	| trailer trailer_rec;

suite: simple_stmt | NEWLINE INDENT stmts DEDENT; 


stmts:    stmt 
	| stmt stmts;

del_stmt: 'del' exprlist;

testlist_safe: old_test testlistsafe_option1 testlistsafe_option2;

testlistsafe_option1: COMMA old_test | COMMA old_test testlistsafe_option1;

testlistsafe_option2: /*empty*/ | COMMA;

old_test: or_test;

%%
struct node *treenode()
{
	struct node *new = (struct node *)malloc(sizeof(struct node));
	new->value= NULL;
	new->leftchild=NULL;
	new->rightchild=NULL;
	return new;
}
void addchild(struct node *parent, struct node *lhs,struct node *rhs)
{
		parent->leftchild=lhs;
		parent->rightchild=rhs;
}
int yyerror(char *s)
{
	fprintf(stderr, "%s\n",s);
}
	
main()
{
	yyparse();
	display();
}
